library(dplyr)
library(sf)
library(tidyverse)
library(leaflet)
library(sf)
library(leaflet.providers)
library(RColorBrewer)
library(tigris)
Dot Density Plot
# education_url <- "https://github.com/dyerlab/ENVS-Lectures/raw/master/data/edu_attainment-shp.zip"
#
# file <- tempfile(pattern = "edu", tmpdir = ".", fileext = ".zip")
# file
#
# download.file(education_url, destfile = file)
# unzip(file, exdir = ".")
#
#
# points <- st_read("edu_attainment-shp")
setwd("~/Spring2021/GISinR/GISinR")
The working directory was changed to C:/Users/Charis/Documents/Spring2021/GISinR/GISinR inside a notebook chunk. The working directory will be reset when the chunk is finished running. Use the knitr root.dir option in the setup chunk to change the working directory for notebook chunks.
points <- st_read("edu_attainment-shp")
Reading layer `edu_attainment' from data source `C:\Users\Charis\Documents\Spring2021\GISinR\GISinR\edu_attainment-shp' using driver `ESRI Shapefile'
Simple feature collection with 15745 features and 1 field
geometry type: POINT
dimension: XY
bbox: xmin: -77.59891 ymin: 37.44779 xmax: -77.38568 ymax: 37.60228
geographic CRS: WGS 84
Convert education levels to factor - this allows us to use colorFactor() to create our color palette
points$education <- factor(points$education, levels = c("No HS diploma", "HS, no Bachelors", "Bachelors" , "Post-Bachelors" ))
Create color palette
factpal <- colorFactor(brewer.pal(n = 4, name = "RdBu"), points$education) #used to color categorical data
Create dot density plot
leaflet(points) %>%
addProviderTiles(providers$CartoDB.Positron)%>% #add provider tiles
addCircles(stroke = FALSE, fillOpacity = 1, #add points
color = ~factpal(education)) %>% #color based on educational attainment
addLegend(pal = factpal, values = ~education, title = "Education Attainment")%>% #add legend
addScaleBar(position = "bottomright") #add scale bar
Choropleth plot
load in the census tract data
tracts <- tracts("VA", "Richmond city") %>%
st_transform(4326)
Using FIPS code '51' for state 'VA'
Using FIPS code '760' for 'Richmond city'
Data Prep
edu_tracts <- tracts %>%
st_buffer(dist = 0) %>% # buffer by 0 to avoid error message
st_intersection(points) # intersect the point data with the tract polygons
edu_tracts %>%
group_by(NAME, education) %>% # group by tract name and education level
tally() -> tally # tally() counts the number of rows for the groups, so output is one row for every attainment level for each tract (so if a tract has all 4 attainment levels, there are 4 rows of data for that tract)
tally <- as.data.frame(tally) # converted to data.frame to be able to drop the geometry because the `pivot_wider()` function would not work the way I wanted it to when the geometry was present
tally <- tally %>%
select(NAME, education, n)%>% # do not want the geometry
pivot_wider(names_from = education, values_from = n) # pivot the table so that instead of having multiple rows per tract, you have one row per tract with a column for each attainment level
tally[is.na(tally)] <- 0 # define NA values as zero
tally
Create attainment metric for choropleth
tally <- tally %>%
mutate(edu = (((`No HS diploma` * 1) + (`HS, no Bachelors` * 2) + (`Bachelors` * 3) + (`Post-Bachelors` * 4))/
(`No HS diploma` + `HS, no Bachelors` + `Bachelors` + `Post-Bachelors`)))
# I created a column, edu, and did a weighted average for each row. So 'No HS diploma' was weighted as 1, 'HS, no Bachelors' as 2, ect.
# I used this new column as my average education attainment value to color my polygons
tally %>%
select(NAME, edu) -> tally # no longer need the individual count data
Join the education data back with the tract data
tracts %>%
left_join(tally, by = "NAME") -> tracts
Create the palette
pal <- colorNumeric(
palette = "RdBu",
domain = tracts$edu) # This time I want a continuos palatte, so I used `colorNumeric()`
Make the choropleth map
leaflet(tracts) %>%
addProviderTiles(providers$CartoDB.Positron)%>% # add provider tiles
addPolygons( fillOpacity = 1, # add tract polygons
fillColor = ~pal(edu), smoothFactor = 0.2, # fill color based on the calculated 'edu' metric
color = "grey",
opacity = 1,
weight = 1) %>%
addLegend(pal = pal, values = ~edu, title = "Education Attainment") # add legend
I did not like this legend, as it’s unclear what the numbers mean. With some googling I found a solution
labels <-c("No HS diploma (1)", "HS, no Bachelors (2)",
"Bachelors (3)" , "Post-Bachelors (4)" ) # define the labels for the legend
leaflet(tracts) %>%
addProviderTiles(providers$CartoDB.Positron)%>% # add provider tiles
addPolygons( fillOpacity = 1, # add tract polygons
fillColor = ~pal(edu), smoothFactor = 0.2, # fill color based on the calculated 'edu' metric
color = "grey",
opacity = 1,
weight = 1) %>%
addLegend(pal = pal, values = ~edu,
opacity = 1,
title = "Education Attainment",
labFormat = function(type, cuts, p) { # Here's the trick
paste0(labels)
})
That looks better, I think
Combine the maps
Final map
LS0tDQp0aXRsZTogIkxlYWZsZXQgSG9tZXdvcmsgS2V5Ig0KYXV0aG9yOiAiQ2hhcmlzIERlYWR3eWxlciINCmRhdGU6ICIzLzE1LzIwMjEiDQpvdXRwdXQ6IGh0bWxfbm90ZWJvb2sNCi0tLQ0KDQpgYGB7cn0NCmxpYnJhcnkoZHBseXIpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeSh0aWR5dmVyc2UpDQpsaWJyYXJ5KGxlYWZsZXQpDQpsaWJyYXJ5KHNmKQ0KbGlicmFyeShsZWFmbGV0LnByb3ZpZGVycykNCmxpYnJhcnkoUkNvbG9yQnJld2VyKQ0KbGlicmFyeSh0aWdyaXMpDQpgYGANCg0KIyMjIERvdCBEZW5zaXR5IFBsb3QNCmBgYHtyfQ0KIyBlZHVjYXRpb25fdXJsIDwtICJodHRwczovL2dpdGh1Yi5jb20vZHllcmxhYi9FTlZTLUxlY3R1cmVzL3Jhdy9tYXN0ZXIvZGF0YS9lZHVfYXR0YWlubWVudC1zaHAuemlwIg0KIyANCiMgZmlsZSA8LSB0ZW1wZmlsZShwYXR0ZXJuID0gImVkdSIsIHRtcGRpciA9ICIuIiwgZmlsZWV4dCA9ICIuemlwIikNCiMgZmlsZQ0KIyANCiMgZG93bmxvYWQuZmlsZShlZHVjYXRpb25fdXJsLCBkZXN0ZmlsZSA9IGZpbGUpDQojIHVuemlwKGZpbGUsIGV4ZGlyID0gIi4iKQ0KIyANCiMgDQojIHBvaW50cyA8LSBzdF9yZWFkKCJlZHVfYXR0YWlubWVudC1zaHAiKQ0KYGBgDQoNCkNvbnZlcnQgZWR1Y2F0aW9uIGxldmVscyB0byBmYWN0b3IgLSB0aGlzIGFsbG93cyB1cyB0byB1c2UgYGNvbG9yRmFjdG9yKClgIHRvIGNyZWF0ZSBvdXIgY29sb3IgcGFsZXR0ZQ0KYGBge3J9DQpwb2ludHMkZWR1Y2F0aW9uIDwtIGZhY3Rvcihwb2ludHMkZWR1Y2F0aW9uLCBsZXZlbHMgPSBjKCJObyBIUyBkaXBsb21hIiwgIkhTLCBubyBCYWNoZWxvcnMiLCAiQmFjaGVsb3JzIiAsICJQb3N0LUJhY2hlbG9ycyIgICkpIA0KYGBgDQoNCkNyZWF0ZSBjb2xvciBwYWxldHRlDQpgYGB7cn0NCmZhY3RwYWwgPC0gY29sb3JGYWN0b3IoYnJld2VyLnBhbChuID0gNCwgbmFtZSA9ICJSZEJ1IiksIHBvaW50cyRlZHVjYXRpb24pICN1c2VkIHRvIGNvbG9yIGNhdGVnb3JpY2FsIGRhdGENCmBgYA0KDQoNCkNyZWF0ZSBkb3QgZGVuc2l0eSBwbG90DQpgYGB7cn0NCmxlYWZsZXQocG9pbnRzKSAlPiUgDQogIGFkZFByb3ZpZGVyVGlsZXMocHJvdmlkZXJzJENhcnRvREIuUG9zaXRyb24pJT4lICNhZGQgcHJvdmlkZXIgdGlsZXMNCiAgYWRkQ2lyY2xlcyhzdHJva2UgPSBGQUxTRSwgIGZpbGxPcGFjaXR5ID0gMSwgI2FkZCBwb2ludHMNCiAgICAgICAgICAgICAgY29sb3IgPSB+ZmFjdHBhbChlZHVjYXRpb24pKSAlPiUgI2NvbG9yIGJhc2VkIG9uIGVkdWNhdGlvbmFsIGF0dGFpbm1lbnQNCiAgYWRkTGVnZW5kKHBhbCA9IGZhY3RwYWwsIHZhbHVlcyA9IH5lZHVjYXRpb24sIHRpdGxlID0gIkVkdWNhdGlvbiBBdHRhaW5tZW50IiklPiUgI2FkZCBsZWdlbmQNCiAgYWRkU2NhbGVCYXIocG9zaXRpb24gPSAiYm90dG9tcmlnaHQiKSAjYWRkIHNjYWxlIGJhcg0KYGBgDQoNCiMjIyBDaG9yb3BsZXRoIHBsb3QNCg0KbG9hZCBpbiB0aGUgY2Vuc3VzIHRyYWN0IGRhdGENCmBgYHtyfQ0KdHJhY3RzIDwtIHRyYWN0cygiVkEiLCAiUmljaG1vbmQgY2l0eSIpICU+JQ0KICBzdF90cmFuc2Zvcm0oNDMyNikNCmBgYA0KDQpEYXRhIFByZXANCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9DQplZHVfdHJhY3RzIDwtIHRyYWN0cyAlPiUNCiAgc3RfYnVmZmVyKGRpc3QgPSAwKSAlPiUgIyBidWZmZXIgYnkgMCB0byBhdm9pZCBlcnJvciBtZXNzYWdlDQogIHN0X2ludGVyc2VjdGlvbihwb2ludHMpICMgaW50ZXJzZWN0IHRoZSBwb2ludCBkYXRhIHdpdGggdGhlIHRyYWN0IHBvbHlnb25zDQpgYGANCg0KYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0NCmVkdV90cmFjdHMgJT4lDQogIGdyb3VwX2J5KE5BTUUsIGVkdWNhdGlvbikgJT4lICMgZ3JvdXAgYnkgdHJhY3QgbmFtZSBhbmQgZWR1Y2F0aW9uIGxldmVsDQogIHRhbGx5KCkgLT4gdGFsbHkgIyB0YWxseSgpIGNvdW50cyB0aGUgbnVtYmVyIG9mIHJvd3MgZm9yIHRoZSBncm91cHMsIHNvIG91dHB1dCBpcyBvbmUgcm93IGZvciBldmVyeSBhdHRhaW5tZW50IGxldmVsIGZvciBlYWNoIHRyYWN0IChzbyBpZiBhIHRyYWN0IGhhcyBhbGwgNCBhdHRhaW5tZW50IGxldmVscywgdGhlcmUgYXJlIDQgcm93cyBvZiBkYXRhIGZvciB0aGF0IHRyYWN0KQ0KDQpgYGANCg0KYGBge3J9DQp0YWxseSA8LSBhcy5kYXRhLmZyYW1lKHRhbGx5KSAjIGNvbnZlcnRlZCB0byBkYXRhLmZyYW1lIHRvIGJlIGFibGUgdG8gZHJvcCB0aGUgZ2VvbWV0cnkgYmVjYXVzZSB0aGUgYHBpdm90X3dpZGVyKClgIGZ1bmN0aW9uIHdvdWxkIG5vdCB3b3JrIHRoZSB3YXkgSSB3YW50ZWQgaXQgdG8gd2hlbiB0aGUgZ2VvbWV0cnkgd2FzIHByZXNlbnQNCg0KdGFsbHkgPC0gdGFsbHkgJT4lDQogIHNlbGVjdChOQU1FLCBlZHVjYXRpb24sIG4pJT4lICMgZG8gbm90IHdhbnQgdGhlIGdlb21ldHJ5IA0KICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gZWR1Y2F0aW9uLCB2YWx1ZXNfZnJvbSA9IG4pICMgcGl2b3QgdGhlIHRhYmxlIHNvIHRoYXQgaW5zdGVhZCBvZiBoYXZpbmcgbXVsdGlwbGUgcm93cyBwZXIgdHJhY3QsIHlvdSBoYXZlIG9uZSByb3cgcGVyIHRyYWN0IHdpdGggYSBjb2x1bW4gZm9yIGVhY2ggYXR0YWlubWVudCBsZXZlbA0KDQp0YWxseVtpcy5uYSh0YWxseSldIDwtIDAgIyBkZWZpbmUgTkEgdmFsdWVzIGFzIHplcm8NCg0KdGFsbHkNCmBgYA0KDQpDcmVhdGUgYXR0YWlubWVudCBtZXRyaWMgZm9yIGNob3JvcGxldGgNCg0KYGBge3J9DQp0YWxseSA8LSB0YWxseSAlPiUNCiAgbXV0YXRlKGVkdSA9ICgoKGBObyBIUyBkaXBsb21hYCAqIDEpICsgKGBIUywgbm8gQmFjaGVsb3JzYCAqIDIpICsgKGBCYWNoZWxvcnNgICogMykgKyAoYFBvc3QtQmFjaGVsb3JzYCAqIDQpKS8NCiAgICAgICAgICAgICAgICAgIChgTm8gSFMgZGlwbG9tYWAgICsgYEhTLCBubyBCYWNoZWxvcnNgICsgYEJhY2hlbG9yc2AgKyBgUG9zdC1CYWNoZWxvcnNgKSkpDQoNCiMgSSBjcmVhdGVkIGEgY29sdW1uLCBlZHUsIGFuZCBkaWQgYSB3ZWlnaHRlZCBhdmVyYWdlIGZvciBlYWNoIHJvdy4gU28gJ05vIEhTIGRpcGxvbWEnIHdhcyB3ZWlnaHRlZCBhcyAxLCAnSFMsIG5vIEJhY2hlbG9ycycgYXMgMiwgZWN0LiANCg0KIyBJIHVzZWQgdGhpcyBuZXcgY29sdW1uIGFzIG15IGF2ZXJhZ2UgZWR1Y2F0aW9uIGF0dGFpbm1lbnQgdmFsdWUgdG8gY29sb3IgbXkgcG9seWdvbnMNCmBgYA0KDQpgYGB7cn0NCnRhbGx5ICU+JQ0KICBzZWxlY3QoTkFNRSwgZWR1KSAtPiB0YWxseSAjIG5vIGxvbmdlciBuZWVkIHRoZSBpbmRpdmlkdWFsIGNvdW50IGRhdGENCmBgYA0KDQpKb2luIHRoZSBlZHVjYXRpb24gZGF0YSBiYWNrIHdpdGggdGhlIHRyYWN0IGRhdGENCg0KYGBge3J9DQp0cmFjdHMgJT4lDQogIGxlZnRfam9pbih0YWxseSwgYnkgPSAiTkFNRSIpIC0+IHRyYWN0cw0KYGBgDQoNCkNyZWF0ZSB0aGUgcGFsZXR0ZQ0KDQpgYGB7cn0NCnBhbCA8LSBjb2xvck51bWVyaWMoDQogIHBhbGV0dGUgPSAiUmRCdSIsDQogIGRvbWFpbiA9IHRyYWN0cyRlZHUpICMgVGhpcyB0aW1lIEkgd2FudCBhIGNvbnRpbnVvcyBwYWxhdHRlLCBzbyBJIHVzZWQgYGNvbG9yTnVtZXJpYygpYA0KYGBgDQoNCk1ha2UgdGhlIGNob3JvcGxldGggbWFwDQoNCmBgYHtyfQ0KbGVhZmxldCh0cmFjdHMpICU+JQ0KICBhZGRQcm92aWRlclRpbGVzKHByb3ZpZGVycyRDYXJ0b0RCLlBvc2l0cm9uKSU+JSAjIGFkZCBwcm92aWRlciB0aWxlcw0KICBhZGRQb2x5Z29ucyggZmlsbE9wYWNpdHkgPSAxLCAjIGFkZCB0cmFjdCBwb2x5Z29ucw0KICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbChlZHUpLCBzbW9vdGhGYWN0b3IgPSAwLjIsICMgZmlsbCBjb2xvciBiYXNlZCBvbiB0aGUgY2FsY3VsYXRlZCAnZWR1JyBtZXRyaWMNCiAgICAgICAgICAgICAgIGNvbG9yID0gImdyZXkiLCANCiAgICAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgICAgd2VpZ2h0ID0gMSkgJT4lDQogIGFkZExlZ2VuZChwYWwgPSBwYWwsIHZhbHVlcyA9IH5lZHUsIHRpdGxlID0gIkVkdWNhdGlvbiBBdHRhaW5tZW50IikgIyBhZGQgbGVnZW5kDQpgYGANCg0KSSBkaWQgbm90IGxpa2UgdGhpcyBsZWdlbmQsIGFzIGl0J3MgdW5jbGVhciB3aGF0IHRoZSBudW1iZXJzIG1lYW4uIFdpdGggc29tZSBnb29nbGluZyBJIGZvdW5kIGEgc29sdXRpb24NCg0KYGBge3J9DQpsYWJlbHMgPC1jKCJObyBIUyBkaXBsb21hICgxKSIsICJIUywgbm8gQmFjaGVsb3JzICgyKSIsDQogICAgICAgICAgICJCYWNoZWxvcnMgKDMpIiAsICJQb3N0LUJhY2hlbG9ycyAoNCkiICApICMgZGVmaW5lIHRoZSBsYWJlbHMgZm9yIHRoZSBsZWdlbmQNCmBgYA0KDQpgYGB7cn0NCmxlYWZsZXQodHJhY3RzKSAlPiUNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbiklPiUgIyBhZGQgcHJvdmlkZXIgdGlsZXMNCiAgYWRkUG9seWdvbnMoIGZpbGxPcGFjaXR5ID0gMSwgIyBhZGQgdHJhY3QgcG9seWdvbnMNCiAgICAgICAgICAgICAgIGZpbGxDb2xvciA9IH5wYWwoZWR1KSwgc21vb3RoRmFjdG9yID0gMC4yLCAjIGZpbGwgY29sb3IgYmFzZWQgb24gdGhlIGNhbGN1bGF0ZWQgJ2VkdScgbWV0cmljDQogICAgICAgICAgICAgICBjb2xvciA9ICJncmV5IiwgDQogICAgICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgICAgIHdlaWdodCA9IDEpICU+JQ0KICBhZGRMZWdlbmQocGFsID0gcGFsLCB2YWx1ZXMgPSB+ZWR1LCANCiAgICAgICAgICAgIG9wYWNpdHkgPSAxLA0KICAgICAgICAgICAgdGl0bGUgPSAiRWR1Y2F0aW9uIEF0dGFpbm1lbnQiLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gZnVuY3Rpb24odHlwZSwgY3V0cywgcCkgeyAgIyBIZXJlJ3MgdGhlIHRyaWNrDQogICAgICAgICAgICAgIHBhc3RlMChsYWJlbHMpDQogICAgICAgICAgICB9KQ0KYGBgDQpUaGF0IGxvb2tzIGJldHRlciwgSSB0aGluaw0KDQojIyMgQ29tYmluZSB0aGUgbWFwcw0KDQpgYGB7cn0NCg0KbGVhZmxldCgpICU+JSAjIEkgZGVjaWRlZCB0byBkZWZpbmUgYnkgZGF0YSBieSBsYXllciBiZWNhdXNlIEkgaGF2ZSBtdWx0aXBsZSBkYXRhIHNldHMNCiAgYWRkUHJvdmlkZXJUaWxlcyhwcm92aWRlcnMkQ2FydG9EQi5Qb3NpdHJvbikgJT4lICMgQWRkIHByb3ZpZGVyIHRpbGVzDQogIGFkZFBvbHlnb25zKGRhdGEgPSB0cmFjdHMsICMgSSBkZWNpZGVkIHRvIHBsb3QgdGhlIHRyYWN0cyBvbiB0aGUgZG90IGRlbnNpdHkgbWFwDQogICAgICAgICAgICAgIGNvbG9yID0gImJsYWNrIiwNCiAgICAgICAgICAgICAgd2VpZ2h0ID0gMSwNCiAgICAgICAgICAgICAgZmlsbE9wYWNpdHkgPSAwLA0KICAgICAgICAgICAgICBncm91cCA9ICJDaXJjbGUiICMgTmVlZCB0byBncm91cHMsIDEgZm9yIGRlbnNpdHkgcGxvdCBhbmQgMSBmb3IgY2hvcm9wbGV0aA0KICAgICAgICAgICAgICApICAlPiUNCiAgYWRkQ2lyY2xlcyhkYXRhID0gcG9pbnRzLA0KICAgICAgICAgICAgIHN0cm9rZSA9IEZBTFNFLCAgZmlsbE9wYWNpdHkgPSAxLCAjcGxvdCB0aGUgY2lyY2xlcyBvbiB0b3Agb2YgdGhlIHRyYWN0cw0KICAgICAgICAgICAgIGNvbG9yID0gfmZhY3RwYWwoZWR1Y2F0aW9uKSwNCiAgICAgICAgICAgICBncm91cCA9ICJDaXJjbGUiICMgRGVmaW5lIGdyb3VwDQogICAgICAgICAgICAgKSAlPiUNCiAgYWRkTGVnZW5kKGRhdGEgPSBwb2ludHMsDQogICAgICAgICAgICBwYWwgPSBmYWN0cGFsLCAjIEFkZCBsZWdlbmQgZm9yIGRvdCBkZW5zaXR5IHBsb3QNCiAgICAgICAgICAgIHZhbHVlcyA9IH5lZHVjYXRpb24sDQogICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgIHRpdGxlID0gIkVkdWNhdGlvbmFsIEF0dGFpbm1lbnQiLA0KICAgICAgICAgICAgZ3JvdXAgPSAiQ2lyY2xlIiAjIERlZmluZSBncm91cCBmb3IgbGVnZW5kDQogICAgICAgICAgICApICU+JQ0KICBncm91cE9wdGlvbnMoIkNpcmNsZSIsIHpvb21MZXZlbHMgPSAxOjEyICMgRGVmaW5lIHRoZSB6b29tIGxldmVscyBmb3IgdGhlIGRvdCBkZW5zaXR5IHBsb3QgKGRvdHMgd2lsbCBvbmx5IGJ5IHZpc2libGUgYmV0d2VlbiB6b29tIGxldmVscyAxIGFuZCAxMikNCiAgICAgICAgICAgICAgICkgJT4lDQogIGFkZFBvbHlnb25zKCBkYXRhID0gdHJhY3RzLCAjIEZpcnN0IGxheWVyIG9mIHRoZSBjaG9yb3BsZXRoIG1hcCwgdHJhY3QgcG9seWdvbnMNCiAgICAgICAgICAgICAgIGZpbGxPcGFjaXR5ID0gLjc1LA0KICAgICAgICAgICAgICAgZmlsbENvbG9yID0gfnBhbChlZHUpLCBzbW9vdGhGYWN0b3IgPSAwLjIsICMgQ29sb3IgZGVmaW5lZCBieSBhdHRhaW5tZW50IG1ldHJpYw0KICAgICAgICAgICAgICAgY29sb3IgPSAiZ3JleSIsDQogICAgICAgICAgICAgICBvcGFjaXR5ID0gMSwNCiAgICAgICAgICAgICAgIHdlaWdodCA9IDEsDQogICAgICAgICAgICAgICBsYWJlbCA9IH5wYXN0ZSgiQXR0YWlubWVudDoiLCByb3VuZChlZHUsIGRpZ2l0cyA9IDIpKSwgIyBBZGRpbmcgYSBsYWJlbCB3aXRoIHRoZSBhdHRhaW5tZW50IG1ldHJpYywgcm91bmRpbmcgdG8gMiBkaWdpdHMgYWZ0ZXIgdGhlIGRlY2ltYWwNCiAgICAgICAgICAgICAgIGdyb3VwID0gIkNob3JvIiAjIENhbGxlZCBteSBzZWNvbmQgZ3JvdXAgIkNob3JvIg0KICAgICAgICAgICAgICAgKSAlPiUNCiAgYWRkTGVnZW5kKGRhdGEgPSB0cmFjdHMsDQogICAgICAgICAgICBwYWwgPSBwYWwsICMgQWRkIGxlZ2VuZCBmb3IgY2hvcm9wbGV0aCBwbG90DQogICAgICAgICAgICB2YWx1ZXMgPSB+ZWR1LA0KICAgICAgICAgICAgb3BhY2l0eSA9IC43NSwNCiAgICAgICAgICAgIHRpdGxlID0gIkVkdWNhdGlvbmFsIEF0dGFpbm1lbnQiLA0KICAgICAgICAgICAgbGFiRm9ybWF0ID0gZnVuY3Rpb24odHlwZSwgY3V0cywgcCkgeyAgIyBIZXJlJ3MgdGhlIHRyaWNrIGFnYWluDQogICAgICAgICAgICAgIHBhc3RlMChsYWJlbHMpDQogICAgICAgICAgICB9LA0KICAgICAgICAgICAgZ3JvdXAgPSAiQ2hvcm8iICMgQWRkIHRvIGNob3JvcGxldGggZ3JvdXANCiAgICAgICAgICAgICkgJT4lDQogZ3JvdXBPcHRpb25zKCJDaG9ybyIsIHpvb21MZXZlbHMgPSAxMzoyMCAgIyBEZWZpbmUgbGV2ZWxzIGZvciB0aGUgY2hvcm9wbGV0aCBtYXAgKGNob3JvcGxldGggcG9seWdvbnMgd2lsbCBvbmx5IGJlIHZpc2JsZSBiZXR3ZWVuIHpvb20gbGV2bHMgMTMgYW5kIDIwKQ0KICAgICAgICAgICAgICApICU+JQ0KICBhZGRTY2FsZUJhcihwb3NpdGlvbiA9ICJib3R0b21yaWdodCIpICMgQWRkIHNjYWxlIGJhci4gU2NhbGUgYmFyIGRvZXMgbm90IG5lZWQgYSBncm91cCBiZWNhdXNlIEkgd2FudCBpdCB2aXNpYmxlIGF0IGFsbCB6b29tIGxldmVscw0KIA0KDQoNCmBgYA0KDQpGaW5hbCBtYXANCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQoNCg0KDQo=